package com.zqh.springframework;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.zqh.app.AppConfig;
import com.zqh.springframework.annotation.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: zqh
 * @CreateTime: 2025-10-07
 * @Description: spring环境
 * @Version: 1.0
 */

public class ApplicationContext {

    private Class<AppConfig> configClass;
    private final Map<String, BeanDefinition> beanDefinitionMap = new LinkedHashMap<>();
    // 一级缓存 单例池
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    // 初始化器的集合
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    public ApplicationContext(Class<AppConfig> configClass) throws Exception {

        this.configClass = configClass;
        // 扫描解析的包
        scan(configClass);

        // 注册beanPostProcessor
        registryBeanPostProcessor();

        // 一个个创建单例bean
        preInstantiateSingletons();

    }


    /**
     * 注册BeanPostProcessor
     * 遍历所有已解析的BeanDefinition，找出实现了BeanPostProcessor接口的类，
     * 将其实例化并添加到beanPostProcessors列表中，以便在后续Bean初始化过程中使用
     * @throws Exception 实例化过程中可能出现的异常
     */
    private void registryBeanPostProcessor() throws Exception {
        // 遍历所有BeanDefinition
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            Class<?> beanClass = beanDefinition.getBeanClass();

            // 判断当前Bean是否实现了BeanPostProcessor接口
            if(BeanPostProcessor.class.isAssignableFrom(beanClass)){
                // 获取Bean实例并加入处理器列表
                BeanPostProcessor bean = (BeanPostProcessor)getBean(beanName);
                beanPostProcessors.add(bean);
            }
        }
//        System.out.println("1");
//        beanPostProcessors.forEach(beanPostProcessor -> {
//            System.out.println("beanPostProcessor:" + beanPostProcessor);
//
//        });
//        System.out.println("2");
    }

    /**
     * 扫描包 定义bean的信息
     * @param configClass
     */
    private void scan(Class<AppConfig> configClass) {
        System.out.println("开始扫描包");
        if (configClass.isAnnotationPresent(ComponentScan.class)){
            // 获取包名
            ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
            System.out.println("包目录：" +  componentScan.value() );
            Set<Class<?>>  packageName = ClassUtil.scanPackage(componentScan.value());

            // 扫描包，判断是否是一个bean类
            for (Class<?> clazz : packageName) {
                System.out.println(clazz);

                // 如果是一个bean 类 ； isAnnotationPresent是判断当前类是否有某个注解
                if(clazz.isAnnotationPresent(Component.class)){
                    // 定义Bean类
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setBeanClass(clazz);

                    // 设置类的类型 默认不是接口
                    beanDefinition.setInterface(clazz.isAnnotationPresent(Interface.class));

                    // 如果没设置默认为单例
                    if(clazz.isAnnotationPresent(Scope.class)){
                        Scope scope = clazz.getAnnotation(Scope.class);
                        beanDefinition.setScope(scope.value());
                    }else {
                        beanDefinition.setScope("singleton");
                    }
                    // 懒加载
                   beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));

                    // component
                    Component component = clazz.getAnnotation(Component.class);
                    String beanName = component.value();

                    if(StrUtil.isEmpty(beanName)){
                        beanName = StrUtil.lowerFirst(clazz.getSimpleName());
                        System.out.println("beanName:" + beanName);
                    }

                    // 放入容器 key beanName value beanDefinition
                    System.out.println("存放bean：");
                    beanDefinitionMap.put(beanName,beanDefinition);

                    beanDefinitionMap.forEach((key,value)->{
                        System.out.println(key + ":" + value);
                    });
                    System.out.println("——————————————————");


                }

            }


        }

        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClass(AutoProxyCreatorBeanPostProcessor.class);
        beanDefinitionMap.put("autoProxyCreatorBeanPostProcessor", beanDefinition);


    }

    /**
     * 预实例化单例bean 判断是否符合实例的条件
     */
    private void preInstantiateSingletons() throws  Exception{
        beanDefinitionMap.forEach((beanName,beanDefinition)->{
            // 单例且非懒加载非接口
            if(beanDefinition.isSingleton() && !beanDefinition.isLazy() && !beanDefinition.isInterface()){
                try {
                    System.out.println("开始创建bean:" + beanName);
                    getBean(beanName);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });

    }

    public Object getBean(String beanName) throws Exception {
        // 从单例池中获取Bean
        Object bean = getSingleton(beanName);
        if (ObjectUtil.isNotNull(bean)) return bean;

        // 没有就创建bean
        // 1、实例化
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        Object instance =  beanClass.getDeclaredConstructor().newInstance();


        // 2、依赖注入
         Field[] fields = instance.getClass().getDeclaredFields();
        Object finalInstance = instance;
        Arrays.stream(fields).forEach(field -> {
            // 判断是否是Autowired
            if(field.isAnnotationPresent(Autowired.class)){
                // byName
                String fieldName = field.getName();
                try {
                    Object fieldBean = getBean(fieldName);
                    field.setAccessible(true);
                    // 设置属性值
                    field.set(finalInstance,fieldBean);

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            }
        });

        // 初始化前
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
        }

        // 3、初始化
        if (instance instanceof InitializingBean) {
            // 回调
            ((InitializingBean) instance).afterPropertiesSet();
        }

        // 初始化后
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
        }

        // 4、放入单例池
        singletonObjects.put(beanName,instance);

        return instance;
    }
    public Object getSingleton(String beanName){

        if(singletonObjects.containsKey(beanName)){
            return singletonObjects.get(beanName);
        }

        return null;
    }






}
